/*
 * @Author: 杰编程 2306248989@qq.com
 * @Date: 2023-07-29 11:49:35
 * @LastEditors: 杰编程 2306248989@qq.com
 * @LastEditTime: 2023-07-29 12:26:52
 * @FilePath: /lesson22/sem/ringQueue.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

const int N = 5;

template <class T>
class RingQueue
{
private:
    void P(sem_t *sem)
    {
        sem_wait(sem);
    }
    void V(sem_t *sem)
    {
        sem_post(sem);
    }
    void lock(pthread_mutex_t *mutex)
    {
        pthread_mutex_lock(mutex);
    }
    void unlock(pthread_mutex_t *mutex)
    {
        pthread_mutex_unlock(mutex);
    }

public:
    RingQueue(int num = N) : _capacity(num), _v(5), _head(0), _tail(0)
    {
        pthread_mutex_init(&_consumer_mutex, nullptr);
        pthread_mutex_init(&_producer_mutex, nullptr);
        sem_init(&_sem_data, 0, 0);
        sem_init(&_sem_room, 0, N);
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&_consumer_mutex);
        pthread_mutex_destroy(&_producer_mutex);
        sem_destroy(&_sem_data);
        sem_destroy(&_sem_room);
    }

    void push(const T &task)
    {
        P(&_sem_room);
        lock(&_producer_mutex);
        _v[_tail++] = task;
        _tail %= _capacity;
        unlock(&_producer_mutex);
        V(&_sem_data);
    }

    void pop(T *out)
    {
        P(&_sem_data);
        lock(&_consumer_mutex);
        *out = _v[_head++];
        _head %= _capacity;
        unlock(&_consumer_mutex);
        V(&_sem_room);
    }

private:
    std::vector<T> _v;
    int _capacity;
    int _head;
    int _tail;
    sem_t _sem_data;
    sem_t _sem_room;
    pthread_mutex_t _consumer_mutex;
    pthread_mutex_t _producer_mutex;
};